﻿using mozhi.smarterp.Finance.Enums;
using Mozhi.Abp.Core.Extensions;
using System;
using Volo.Abp;

namespace mozhi.smarterp.Finance.Accounts
{
    /// <summary>
    /// 科目余额
    /// </summary>
    public class AccountBalance : AggregateRootBase<Guid>
    {
        /// <summary>
        /// 科目
        /// </summary>
        public Guid AccountId { private set; get; }

        /// <summary>
        /// 期间
        /// </summary>
        public int Period { private set; get; }

        /// <summary>
        /// 币别
        /// </summary>
        public Guid? CurrencyId { private set; get; }

        /// <summary>
        /// 核算维度Id
        /// </summary>
        public Guid? DimensionGroupValueId { private set; get; }

        /// <summary>
        /// 方向
        /// </summary>
        public AccountDirectionType Direction { private set; get; }

        /// <summary>
        /// 期初余额
        /// </summary>
        public decimal? OpeningAmount { private set; get; }

        /// <summary>
        /// 期初余额原币
        /// </summary>
        public decimal? OpeningAmountFr { private set; get; }


        /// <summary>
        /// 本期借方发生额
        /// </summary>
        public decimal? DebitAmount { private set; get; }

        /// <summary>
        /// 本期借方发生额原币
        /// </summary>
        public decimal? DebitAmountFr { private set; get; }

        /// <summary>
        /// 本期贷方发生额
        /// </summary>
        public decimal? CreditAmount { private set; get; }

        /// <summary>
        /// 本期贷方发生额原币
        /// </summary>
        public decimal? CreditAmountFr { private set; get; }

        /// <summary>
        /// 本年累计借方发生额
        /// </summary>
        public decimal? CurrentYearDebitAmount { set; get; }

        /// <summary>
        /// 本年累计借方发生额原币
        /// </summary>
        public decimal? CurrentYearDebitAmountFr { set; get; }

        /// <summary>
        /// 本年累计贷方发生额
        /// </summary>
        public decimal? CurrentYearCreditAmount { set; get; }

        /// <summary>
        /// 本年累计贷方发生额原币
        /// </summary>
        public decimal? CurrentYearCreditAmountFr { set; get; }

        /// <summary>
        /// 期末余额
        /// </summary>
        public decimal? ClosingAmount { set; get; }

        /// <summary>
        /// 期末余额原币
        /// </summary>
        public decimal? ClosingAmountFr { set; get; }

        private AccountBalance(){}

        public AccountBalance(Guid id, Guid accountId, Guid? currencyId, int period, Guid? dimensionGroupValueId, AccountDirectionType direction)
        {
            Id = id;
            AccountId = accountId;
            CurrencyId = currencyId;
            Period = period;
            DimensionGroupValueId = dimensionGroupValueId;
            Direction = direction;

            Validate();
        }

        public void ChangeAmount(bool isForeignCurrency, Guid baseCurrencyId, Guid? bankAccountCurrencyId,
            decimal? opengingAmount, decimal? openingAmountFr,
            decimal? currentYearDebitAmount, decimal? currentYearDebitAmountFr,
            decimal? currentYearCreditAmount, decimal? currentYearCreditAmountFr,
            decimal? debitAmount, decimal? debitAmountFr, decimal? creditAmount, decimal? creditAmountFr)
        {
            if (!isForeignCurrency && CurrencyId.HasValue && CurrencyId != baseCurrencyId)
                throw new UserFriendlyException("非外币核算科目，不能录入非本位币金额", "100000");

            if (CurrencyId.HasValue && bankAccountCurrencyId != null && CurrencyId != bankAccountCurrencyId)
                throw new UserFriendlyException("资金账号科目，不能录入非银行币别金额", "100000");

            bool isFirstMonth = Period.ToLastDayDateTime().Month == 1;

            this.OpeningAmountFr = openingAmountFr;
            this.CurrentYearDebitAmountFr = currentYearDebitAmountFr;
            this.CurrentYearCreditAmountFr = currentYearCreditAmountFr;
            this.CreditAmountFr = creditAmountFr;
            this.DebitAmountFr = debitAmountFr;
            
            if (!isForeignCurrency)
            {
                this.OpeningAmount = openingAmountFr;
                this.CurrentYearDebitAmount = isFirstMonth ? null : currentYearDebitAmountFr;
                this.CurrentYearCreditAmount = isFirstMonth ? null : currentYearCreditAmountFr;
                this.DebitAmount = debitAmountFr;
                this.CreditAmount = creditAmountFr;
            }
            else
            {
                this.OpeningAmount = opengingAmount;
                this.CurrentYearDebitAmount = isFirstMonth ? null : currentYearDebitAmount;
                this.CurrentYearCreditAmount = isFirstMonth ? null : currentYearCreditAmount;
                this.DebitAmount = debitAmount;
                this.CreditAmount = creditAmount;
            }

            CalculateClosingAmount();

        }

        public void ChangeAmountDirection()
        {
            OpeningAmount = OpeningAmount.HasValue ? -1 * OpeningAmount.Value : null;
            OpeningAmountFr = OpeningAmountFr.HasValue ? -1 * OpeningAmountFr.Value : null;
            DebitAmount = DebitAmount.HasValue ? -1 * DebitAmount.Value : null;
            DebitAmountFr = DebitAmountFr.HasValue ? -1 * DebitAmountFr.Value : null;
            CreditAmount = CreditAmount.HasValue ? -1 * CreditAmount.Value : null;
            CreditAmountFr = CreditAmountFr.HasValue ? -1 * CreditAmountFr.Value : null;
            CurrentYearDebitAmount = CurrentYearDebitAmount.HasValue ? -1 * CurrentYearDebitAmount.Value : null;
            CurrentYearDebitAmountFr = CurrentYearDebitAmountFr.HasValue ? -1 * CurrentYearDebitAmountFr.Value : null;
            CurrentYearCreditAmount = CurrentYearCreditAmount.HasValue ? -1 * CurrentYearCreditAmount.Value : null;
            CurrentYearCreditAmountFr = CurrentYearCreditAmountFr.HasValue ? -1 * CurrentYearCreditAmountFr.Value : null;
            ClosingAmount = ClosingAmount.HasValue ? -1 * ClosingAmount.Value : null;
            ClosingAmountFr = ClosingAmountFr.HasValue ? -1 * ClosingAmountFr.Value : null;
        }

        public void ChangeCurrentAmount(decimal? debitAmount, decimal? debitAmountFr, decimal? creditAmount, decimal? creditAmountFr)
        {
            this.CreditAmount = creditAmount;
            this.CreditAmountFr = creditAmountFr;

            this.DebitAmount = debitAmount;
            this.DebitAmountFr = debitAmountFr;

            CalculateClosingAmount();
        }


        public void ChangeCurrentYearAmount(decimal? debitAmount,  decimal? creditAmount)
        {
            this.CurrentYearCreditAmount = creditAmount;

            this.CurrentYearDebitAmount = debitAmount;
        }

        public void ChangeOpeningAmount(decimal? openingAmount , decimal? openingAmountFr)
        {
            OpeningAmount = openingAmount;
            OpeningAmountFr = openingAmountFr;

            CalculateClosingAmount();
        }

        public void ChangePeriod(int period)
        {
            Period = period;
        }

        #region
        private void Validate()
        {
            if (AccountId == default)
                throw new UserFriendlyException("科目不能为空", "100000");

            if (Period == 0)
                throw new UserFriendlyException("期间不能为空", "100000");

            if (Direction == default)
                throw new UserFriendlyException("余额方向不能为空");
        }

        private void CalculateClosingAmount()
        {
            ClosingAmountFr = Direction == AccountDirectionType.Debit ?
               (OpeningAmountFr ?? 0) + (DebitAmountFr ?? 0) - (CreditAmountFr ?? 0) : (OpeningAmountFr ?? 0) + (CreditAmountFr ?? 0) - (DebitAmountFr ?? 0);
           ClosingAmount = Direction == AccountDirectionType.Debit ?
              (OpeningAmount ?? 0) + (DebitAmount ?? 0) - (CreditAmount ?? 0) : (OpeningAmount ?? 0) + (CreditAmount ?? 0) - (DebitAmount ?? 0);
        }
        #endregion
    }
}
